#include "frame_util.h"

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <hiredis/hiredis.h>
#include "data_type.h"
#include "redis_util.h"

extern uint8_t *sn;

/**
 * @brief 查找数据包里面的结束字符位置
 * 
 * @param str 原始数据缓冲区
 * @param c 结束字符
 * @param len 原始数据长度
 * @return uint8_t* 找到字符后返回其后部分（包括结尾的空字符）
 */
uint8_t* find_substring(uint8_t *str, uint8_t c, uint16_t len) {
    int i = 0;
    if (str == NULL) {
        return NULL;
    }
    // 遍历字符串直到找到目标字符或到达结尾
    printf("FindSub:");
    while (i < len) {
        printf("%02X ", *(str + i));
        if (i > 0 && (*(str + i -1)<<8 | *(str+i)) == 0xA5A3) {
            i++;
        } else if(i > 0 && i < (len-1) && ((*(str+i-1)<<8 | *(str+i)) == 0xA3A3 || (*(str + i)<<8 | *(str+i+1)) == 0xA3A3)){
            i = i+2;
        } else if(*(str + i) == c) {
            break;
        } else {
            i++;
        }
    }
    printf("\n");
    // 找到字符后返回其后部分（包括结尾的空字符）
    return (*(str+i) == c) ? str + i : NULL;
}

/**
 * @brief 编码数据帧：添加帧头、转义字符、CRC 校验和帧尾
 * 
 * @param input 原始数据缓冲区
 * @param input_len 原始数据长度
 * @param output 输出缓冲区指针（由函数分配内存）
 * @return uint16_t 编码后数据长度
 */
uint16_t encode_frame(uint8_t *input, uint16_t input_len, uint8_t **output) {
    // 计算编码后的最大可能长度
    uint16_t max_encoded_len = input_len * 2 + 3; // A5 + data + A3 + CRC (2 bytes)
    *output = (uint8_t *)malloc(max_encoded_len);
    if(*output == NULL) {
        perror("Memory allocation failed");
        exit(EXIT_FAILURE);
    }

    uint16_t j = 0;
    // 添加帧头
    (*output)[j++] = 0xA5;

    // 编码有效数据
    for(uint16_t i = 0; i < input_len; i++) {
        if(input[i] == 0xA5) {
            (*output)[j++] = 0xA5;
            (*output)[j++] = 0xA3;
        }
        else if(input[i] == 0xA3) {
            (*output)[j++] = 0xA3;
            (*output)[j++] = 0xA3;
        }
        else {
            (*output)[j++] = input[i];
        }
    }

    // 计算 CRC（不包括帧头和 CRC 自身）
    uint16_t crc = rtu_crc((*output) + 1, j - 1);

    // 插入 CRC（低位在前）
    
    
    (*output)[j++] = crc & 0xFF;
    (*output)[j++] = (crc >> 8) & 0xFF;
    // 添加帧尾
    (*output)[j++] = 0xA3;

    return j;
}

/**
 * @brief 解码数据帧：去除帧头、转义字符、验证 CRC 和帧尾
 * 
 * @param input 接收到的数据缓冲区
 * @param length 接收到的数据长度
 * @param output 输出缓冲区指针（由函数分配内存）
 * @return uint16_t 解码后数据长度，若失败则返回 0
 */
uint16_t decode_frame(uint8_t *input, uint16_t length, uint8_t **output) {
    if(length < 4) { // 最小帧长度：A5 + 数据 + CRC + A3
        return 0;
    }

    // 查找最后一个 A3 作为帧尾
    uint16_t frame_end = length - 1;
    while(frame_end > 0 && input[frame_end] != 0xA3)
        frame_end--;

    if(frame_end == 0) // 没有找到帧尾
        return 0;

    uint16_t payload_crc_len = frame_end; // 包括 CRC
    uint16_t payload_start = 1; // 帧头后

    // 分配输出缓冲区
    *output = (uint8_t *)malloc(payload_start + (payload_crc_len - 3)); // 不包括 CRC 和 A3
    if(*output == NULL) {
        perror("Memory allocation failed");
        exit(EXIT_FAILURE);
    }

    uint16_t j = 0;
    for(uint16_t i = payload_start; i < payload_crc_len; i++) {
        if(i + 1 < payload_crc_len) {
            if(input[i] == 0xA5 && input[i + 1] == 0xA3) {
                (*output)[j++] = 0xA5;
                i++; // 跳过下一个字节
            }
            else if(input[i] == 0xA3 && input[i + 1] == 0xA3) {
                (*output)[j++] = 0xA3;
                i++; // 跳过下一个字节
            }
            else {
                (*output)[j++] = input[i];
            }
        }
        else {
            // 最后一个字节无法形成配对，按原样处理或忽略
            (*output)[j++] = input[i];
        }
    }

    // 提取 CRC（高位在后）
    uint16_t received_crc = (input[payload_crc_len - 1] << 8) | input[payload_crc_len - 2];

    // 计算解码后数据的 CRC
    uint16_t calculated_crc = rtu_crc(&input[1], length-4);
    printf("CRC:%04X\n", calculated_crc);
    if(received_crc != calculated_crc) {
        printf("CRC 校验失败。\n");
        free(*output);
        *output = NULL;
        return 0;
    }

    return j;
}

/**
 * @brief 解析数据帧，把解决装到结构体数据里面
 * 
 * @param input 需要解析的数据帧
 * @param length 解析的数据长度
 * @return LoraData 解析后的结构体数据
 */
void parse_frame(uint8_t *input, uint16_t length, LoraData *frame){
    if (length < 5){
        return NULL;
    }
    frame->dev_num = input[0]<<8 | input[1];
    frame->type = input[2];
    frame->len = input[3]<<8 | input[4];
    memmove(frame->data, input+5, length -5);
}

/**
 * @brief 解析电源系统状态数据，并把数据组装为JSON格式存放到Redis中
 * 
 * @param data 需要解析的数据帧
 */
char *parse_mppt(LoraData data){
    uint8_t *bRecvBuf = data.data;
    uint8_t device_sn[50]={0}, modelNumber[50]={0};
    uint8_t key[4]={0};
    StEnergyInfo energyAck;
    cJSON *root = cJSON_CreateObject();
    printf("1\n");
    sprintf(key, "%04X", data.dev_num);
    printf("key:%s\n", key);
    int res = redis_pull_data("config_devs", key, device_sn);
    if(res == -1) return NULL;
    printf("key1:%s\n", key);
    if(device_sn == NULL) return NULL;
    printf("sn:%s\n", device_sn);
    EP_JSON_SET_STR(root, "sn", device_sn);
    EP_JSON_SET_INT(root, "dataType", 5);
    EP_JSON_SET_INT(root, "version", 1);

    cJSON *enertyData = cJSON_CreateObject();
    sprintf(modelNumber, "%sDY1", device_sn);
    EP_JSON_SET_STR(enertyData, "modelNumber", modelNumber);
    cJSON *statusData = cJSON_CreateObject();
    /**
     * 解析电源模块当前状态
     */
    energyAck.powerStatus = *bRecvBuf;
    EP_JSON_SET_INT(statusData, "powerStatus", energyAck.powerStatus);
    printf("模块状态:%d\n", energyAck.powerStatus);
    energyAck.offTime = ((*(bRecvBuf+1) << 8) + *(bRecvBuf+2));
    EP_JSON_SET_INT(statusData, "offTime", energyAck.offTime);
    printf("休眠时长:%dm\n", energyAck.offTime);
    energyAck.onTime = ((*(bRecvBuf+3) << 8) + *(bRecvBuf+4));
    EP_JSON_SET_INT(statusData, "onTime", energyAck.onTime);
    printf("唤醒时长:%dm\n", energyAck.onTime);
    cJSON_AddItemToObject(enertyData,"statusData",statusData);
   
    /**
     * 解析电源模块电量信息
     */
    cJSON *powerData = cJSON_CreateObject();
    energyAck.batteryVoltage = (float)((*(bRecvBuf+5) << 8) + *(bRecvBuf+6))/100;
    EP_JSON_SET_INT(powerData, "batteryVoltage", energyAck.batteryVoltage);
    printf("电池电压:%f\n", energyAck.batteryVoltage);
    energyAck.batteryElectric = (float)((*(bRecvBuf+7)<<8) + *(bRecvBuf+8))/1000;
    EP_JSON_SET_INT(powerData, "batteryElectric", energyAck.batteryElectric);
    printf("电池电流:%f\n", energyAck.batteryElectric);
    energyAck.batteryCapacity =  *(bRecvBuf+9);
    EP_JSON_SET_INT(powerData, "batteryCapacity", energyAck.batteryCapacity);
    printf("电池余量:%d\n", energyAck.batteryCapacity);
    energyAck.batteryStatus = *(bRecvBuf+5);
    EP_JSON_SET_INT(powerData, "batteryStatus", energyAck.batteryStatus);
    printf("电池状态:%d\n", energyAck.batteryStatus);

    energyAck.loadVoltage = (float)((*(bRecvBuf+11)<<8) + *(bRecvBuf+12))/100;
    EP_JSON_SET_INT(powerData, "loadVoltage", energyAck.loadVoltage);
    printf("负载电压:%f\n", energyAck.loadVoltage);
    energyAck.loadElectric = (float)((*(bRecvBuf+13)<<8) + *(bRecvBuf+14))/1000;
    EP_JSON_SET_INT(powerData, "loadElectric", energyAck.loadElectric);
    printf("负载电流:%f\n", energyAck.loadElectric);
    energyAck.loadPower = (float)((*(bRecvBuf+15)<<8) + *(bRecvBuf+16))/100;
    EP_JSON_SET_INT(powerData, "loadPower", energyAck.loadPower);
    printf("负载功率:%f\n", energyAck.loadPower);
    energyAck.loadStatus = *(bRecvBuf+17);
    EP_JSON_SET_INT(powerData, "loadStatus", energyAck.loadStatus);
    printf("负载状态:%d\n", energyAck.loadStatus);

    energyAck.columnVoltage = (float)((*(bRecvBuf+18)<<8) + *(bRecvBuf+19))/100;
    EP_JSON_SET_INT(powerData, "columnVoltage", energyAck.columnVoltage);
    printf("阵列电压:%f\n", energyAck.columnVoltage);
    energyAck.columnStatus = *(bRecvBuf+20);
    EP_JSON_SET_INT(powerData, "columnStatus", energyAck.columnStatus);
    printf("阵列状态:%d\n", energyAck.columnStatus);

    energyAck.runDay = (*(bRecvBuf+21)<<8) + *(bRecvBuf+22);
    EP_JSON_SET_INT(powerData, "runDay", energyAck.runDay);
    printf("运行天数:%d\n", energyAck.runDay);
    energyAck.lowVolCnt = (*(bRecvBuf+23)<<8) + *(bRecvBuf+24);
    EP_JSON_SET_INT(powerData, "lowVolCnt", energyAck.lowVolCnt);
    printf("欠压次数:%d\n", energyAck.lowVolCnt);
    energyAck.todayDischarge = (*(bRecvBuf+25)<<8) + *(bRecvBuf+26);
    EP_JSON_SET_INT(powerData, "todayDischarge", energyAck.todayDischarge);
    printf("今日总放电量:%d\n", energyAck.todayDischarge);
    energyAck.yesterdayDischarge = (*(bRecvBuf+27)<<8) + *(bRecvBuf+28);
    EP_JSON_SET_INT(powerData, "yesterdayDischarge", energyAck.yesterdayDischarge);
    printf("昨日总放电量:%d\n", energyAck.yesterdayDischarge);
    energyAck.totalDischarge = (*(bRecvBuf+29)<<32) + (*(bRecvBuf+30)<<16) + (*(bRecvBuf+31)<<8) + *(bRecvBuf+32);
    EP_JSON_SET_INT(powerData, "totalDischarge", energyAck.totalDischarge);
    printf("累计总放电量:%ld\n", energyAck.totalDischarge);
    energyAck.todayCharge = (*(bRecvBuf+33)<<8) + *(bRecvBuf+34);
    EP_JSON_SET_INT(powerData, "todayCharge", energyAck.todayCharge);
    printf("今日总充电量:%d\n", energyAck.todayCharge);
    energyAck.yesterdayCharge = (*(bRecvBuf+35)<<8) + *(bRecvBuf+36);
    EP_JSON_SET_INT(powerData, "yesterdayCharge", energyAck.yesterdayCharge);
    printf("昨日总充电量:%d\n", energyAck.yesterdayCharge);
    energyAck.totalCharge = (*(bRecvBuf+32)<<37) + (*(bRecvBuf+38)<<16) + (*(bRecvBuf+39)<<8) + *(bRecvBuf+40);
    EP_JSON_SET_INT(powerData, "totalCharge", energyAck.totalCharge);
    printf("累计总充电量:%ld\n", energyAck.totalCharge);
    energyAck.fDevTemperature = (float)((*(bRecvBuf+41)<<8) + *(bRecvBuf+42))/10;
    EP_JSON_SET_INT(powerData, "fDevTemperature", energyAck.fDevTemperature);
    printf("控制器内部温度:%f\n", energyAck.fDevTemperature);
    energyAck.fBatTemperature = (float)((*(bRecvBuf+43)<<8) + *(bRecvBuf+44))/10;
    EP_JSON_SET_INT(powerData, "fBatTemperature", energyAck.fBatTemperature);
    printf("控制器外部温度:%f\n", energyAck.fBatTemperature);

    cJSON_AddItemToObject(enertyData,"powerData",powerData);
    cJSON_AddItemToObject(root,"data",enertyData);
    char *str = cJSON_Print(root);

    uint8_t num[4];
    sprintf(num, "%04X", data.dev_num);
    redis_push_data("devlist",num, str);

    cJSON_Delete(root);
    return str;
}

#if 0
/**
 * @brief 解析电源系统状态数据，并把数据组装为JSON格式存放到Redis中
 * 
 * @param data 需要解析的数据帧
 */
char *parse_mppt(LoraData data){
    uint8_t *bRecvBuf = data.data;
    StEnergyInfo energyAck;
    cJSON *root = cJSON_CreateObject();
    EP_JSON_SET_INT(root, "devNum", data.dev_num);

    /**
     * 解析电源模块当前状态
     */
    energyAck.powerStatus = *bRecvBuf;
    EP_JSON_SET_INT(root, "powerStatus", energyAck.powerStatus);
    printf("模块状态:%d\n", energyAck.powerStatus);
    energyAck.offTime = ((*(bRecvBuf+1) << 8) + *(bRecvBuf+2));
    EP_JSON_SET_INT(root, "offTime", energyAck.offTime);
    printf("休眠时长:%dm\n", energyAck.offTime);
    energyAck.onTime = ((*(bRecvBuf+3) << 8) + *(bRecvBuf+4));
    EP_JSON_SET_INT(root, "onTime", energyAck.onTime);
    printf("唤醒时长:%dm\n", energyAck.onTime);
    /**
     * 解析电源模块电量信息
     */
    energyAck.batteryVoltage = (float)((*(bRecvBuf+5) << 8) + *(bRecvBuf+6))/100;
    EP_JSON_SET_INT(root, "batteryVoltage", energyAck.batteryVoltage);
    printf("电池电压:%f\n", energyAck.batteryVoltage);
    energyAck.batteryElectric = (float)((*(bRecvBuf+7)<<8) + *(bRecvBuf+8))/1000;
    EP_JSON_SET_INT(root, "batteryElectric", energyAck.batteryElectric);
    printf("电池电流:%f\n", energyAck.batteryElectric);
    energyAck.batteryCapacity =  *(bRecvBuf+9);
    EP_JSON_SET_INT(root, "batteryCapacity", energyAck.batteryCapacity);
    printf("电池余量:%d\n", energyAck.batteryCapacity);
    energyAck.batteryStatus = *(bRecvBuf+5);
    EP_JSON_SET_INT(root, "batteryStatus", energyAck.batteryStatus);
    printf("电池状态:%d\n", energyAck.batteryStatus);

    energyAck.loadVoltage = (float)((*(bRecvBuf+11)<<8) + *(bRecvBuf+12))/100;
    EP_JSON_SET_INT(root, "loadVoltage", energyAck.loadVoltage);
    printf("负载电压:%f\n", energyAck.loadVoltage);
    energyAck.loadElectric = (float)((*(bRecvBuf+13)<<8) + *(bRecvBuf+14))/1000;
    EP_JSON_SET_INT(root, "loadElectric", energyAck.loadElectric);
    printf("负载电流:%f\n", energyAck.loadElectric);
    energyAck.loadPower = (float)((*(bRecvBuf+15)<<8) + *(bRecvBuf+16))/100;
    EP_JSON_SET_INT(root, "loadPower", energyAck.loadPower);
    printf("负载功率:%f\n", energyAck.loadPower);
    energyAck.loadStatus = *(bRecvBuf+17);
    EP_JSON_SET_INT(root, "loadStatus", energyAck.loadStatus);
    printf("负载状态:%d\n", energyAck.loadStatus);

    energyAck.columnVoltage = (float)((*(bRecvBuf+18)<<8) + *(bRecvBuf+19))/100;
    EP_JSON_SET_INT(root, "columnVoltage", energyAck.columnVoltage);
    printf("阵列电压:%f\n", energyAck.columnVoltage);
    energyAck.columnStatus = *(bRecvBuf+20);
    EP_JSON_SET_INT(root, "columnStatus", energyAck.columnStatus);
    printf("阵列状态:%d\n", energyAck.columnStatus);

    energyAck.runDay = (*(bRecvBuf+21)<<8) + *(bRecvBuf+22);
    EP_JSON_SET_INT(root, "runDay", energyAck.runDay);
    printf("运行天数:%d\n", energyAck.runDay);
    energyAck.lowVolCnt = (*(bRecvBuf+23)<<8) + *(bRecvBuf+24);
    EP_JSON_SET_INT(root, "lowVolCnt", energyAck.lowVolCnt);
    printf("欠压次数:%d\n", energyAck.lowVolCnt);
    energyAck.todayDischarge = (*(bRecvBuf+25)<<8) + *(bRecvBuf+26);
    EP_JSON_SET_INT(root, "todayDischarge", energyAck.todayDischarge);
    printf("今日总放电量:%d\n", energyAck.todayDischarge);
    energyAck.yesterdayDischarge = (*(bRecvBuf+27)<<8) + *(bRecvBuf+28);
    EP_JSON_SET_INT(root, "yesterdayDischarge", energyAck.yesterdayDischarge);
    printf("昨日总放电量:%d\n", energyAck.yesterdayDischarge);
    energyAck.totalDischarge = (*(bRecvBuf+29)<<32) + (*(bRecvBuf+30)<<16) + (*(bRecvBuf+31)<<8) + *(bRecvBuf+32);
    EP_JSON_SET_INT(root, "totalDischarge", energyAck.totalDischarge);
    printf("累计总放电量:%ld\n", energyAck.totalDischarge);
    energyAck.todayCharge = (*(bRecvBuf+33)<<8) + *(bRecvBuf+34);
    EP_JSON_SET_INT(root, "todayCharge", energyAck.todayCharge);
    printf("今日总充电量:%d\n", energyAck.todayCharge);
    energyAck.yesterdayCharge = (*(bRecvBuf+35)<<8) + *(bRecvBuf+36);
    EP_JSON_SET_INT(root, "yesterdayCharge", energyAck.yesterdayCharge);
    printf("昨日总充电量:%d\n", energyAck.yesterdayCharge);
    energyAck.totalCharge = (*(bRecvBuf+32)<<37) + (*(bRecvBuf+38)<<16) + (*(bRecvBuf+39)<<8) + *(bRecvBuf+40);
    EP_JSON_SET_INT(root, "totalCharge", energyAck.totalCharge);
    printf("累计总充电量:%ld\n", energyAck.totalCharge);
    energyAck.fDevTemperature = (float)((*(bRecvBuf+41)<<8) + *(bRecvBuf+42))/10;
    EP_JSON_SET_INT(root, "fDevTemperature", energyAck.fDevTemperature);
    printf("控制器内部温度:%f\n", energyAck.fDevTemperature);
    energyAck.fBatTemperature = (float)((*(bRecvBuf+43)<<8) + *(bRecvBuf+44))/10;
    EP_JSON_SET_INT(root, "fBatTemperature", energyAck.fBatTemperature);
    printf("控制器外部温度:%f\n", energyAck.fBatTemperature);
    char *str = cJSON_Print(root);

    uint8_t num[4];
    sprintf(num, "%04X", data.dev_num);
    redis_push_data(num, str);

    cJSON_Delete(root);
    return str;
}
#endif